#include "Pikmen.h"

#include "setBehavior.h"
#include "Behavior/AllBehavior.h"
#include "Behavior/setSeek.h"
#include "Behavior/setFormation.h"
#include "Behavior/setAlejar.h"
#include "CApp.h"

#include "AnimationPikmenDown.h"
#include "AnimationPikmenUp.h"
#include "AnimationPikmenRight.h"
#include "AnimationPikmenLeft.h"
#include "AnimationPikmenBall.h"

#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>

#include <SDL/SDL.h>
#include <SDL/SDL_gfxPrimitives.h>
#include <SDL/SDL_rotozoom.h>

Pikmen::Pikmen(){
  this->timeOlor = 100;
  this->oldTimetoOlor = -10000;
  this->max_life = LIFE_PIKMEN;
}

bool Pikmen::OnInit(Character* target){
  return true;
}

/*
 * Inicializa al bicho
 */
bool Pikmen::OnInit(vector<Character*>* ch,vector<Obstacle*>* ob,vector<Character*> *en,int posX, int posY,Character* target){
//Behavior *beh;

//if((surface = CSurface::OnLoad("images/dummy.png",true)) == NULL){
//  cout << "Algo salio mal" << endl;
//  return false;
//}
//if((carita = CSurface::OnLoad("images/dummy_head.png",true)) == NULL){
//  cout << "Algo salio mal" << endl;
//  return false;
//}

    // animaciones...
    animations.push_back(new AnimationPikmenUp());
    animations.push_back(new AnimationPikmenRight());
    animations.push_back(new AnimationPikmenDown());
    animations.push_back(new AnimationPikmenLeft());
    animations.push_back(new AnimationPikmenBall());
    currentAnimation = animations[0];
    _animation_oldtime = SDL_GetTicks();

  /* Posicionamos el personaje */
  k = new Kinematic();
  k->position[0] = posX;
  k->position[1] = posY;
  k->orientation = M_PI*((float) (random()%7))/7;
  k->max_velocity = 0.08;
  k->max_rotation = 0.004;
  this->width = 30;
  this->height = 15;
  
//estado = WAITING;
  player = target;
  behaviors.push_back(new setFormation(this,target,ch,ob));
  behaviors.push_back(new Waiting(this,ch,ob));
  behaviors.push_back(new setAlejar(this,target,ch,ob));
  behaviors.push_back(new setSeek(this,this,ch,ob));
  behaviors.push_back(new setSeek(this,this,ch,ob));
  behaviors.push_back(new setSeek(this,this,ch,ob));
  state = new WaitingP(behaviors[1]);
  enemys = en;
  /* Le asignamos sus 3 puntos de vida */
  life = LIFE_PIKMEN;
  max_life = LIFE_PIKMEN;

//cout << "Salio del OnInit de Pikmen.cpp" << endl;
  return true;
}


/*
 * Pinta al bicho
 */
void Pikmen::OnRender(SDL_Surface* display){
  int fakeX, fakeY;
  int fakeW, fakeH,fakeZ,desplazamiento=0;
  double factorK = .003;
  SDL_Surface *animationFrame, *auxFrame;

  // Hacemos render general
  Character::OnRender(display);

  Platform* p = theApp.getPlatform(k->position);
  if (p == NULL)
    fakeZ =0;
  else
    fakeZ = p->position[2];
  /// Primero una sombra
  if (p && abs(fakeZ-k->position[2]) < 1){
    fakeW = width/2;
    fakeH = height/2;
    fakeX = this->k->position[0];
    fakeY = this->k->position[1]-50;
    desplazamiento= -50;
  }
  else{
    fakeW = width/2-k->position[2]*factorK;
    fakeH = height/2-k->position[2]*factorK;
    fakeX = this->k->position[0];
    fakeY = this->k->position[1];
  }
  filledEllipseRGBA(display,
      fixX(fakeX),fixY(fakeY),
      fakeW, fakeH,
      0, 0, 0, 128
      );
  /// Puntero de direccion
  fakeX = k->position[0] + fakeW*cos(k->orientation-M_PI/2);
  fakeY = k->position[1] + fakeH*-sin(k->orientation-M_PI/2)+desplazamiento;
  filledEllipseRGBA(display,
      fixX(fakeX), fixY(fakeY),
      width/8, height/6,
      0, 60, 0, 200
      );

  /// Sprite de la animacion
    if( length(k->velocity) < 0.000001 ){
        animationFrame = CSurface::Copy(
                currentAnimation->getFrame(),
                0, 0,
                currentAnimation->getWidth(),
                currentAnimation->getHeight()
                );
    } else {
        animationFrame = CSurface::Copy(
                currentAnimation->getFrame(),
                currentAnimation->getX(),
                currentAnimation->getY(),
                currentAnimation->getWidth(),
                currentAnimation->getHeight()
                );
    }
    fakeW = width+k->position[2]*factorK;
    fakeH = height+k->position[2]*factorK;

    // if( fakeW/width != 1.0 ){
        auxFrame = zoomSurface(animationFrame,
                fakeW/width,
                fakeH/height,
                SMOOTHING_OFF);
        SDL_FreeSurface(animationFrame);
        animationFrame = auxFrame;
        CSurface::Transparent(animationFrame, 101, 102, 103);
        zoomSurfaceSize(
                width, height,
                fakeW/width, fakeH/height,
                &fakeW, &fakeH);
    // }
    fakeX = k->position[0]-currentAnimation->getWidth()/2;
    fakeY = k->position[1]-currentAnimation->getHeight()+3-k->position[2]*.065;
    fakeX -= fakeW - width;
    fakeY -= fakeH - height;

    CSurface::OnDraw(display, animationFrame, fixX(fakeX), fixY(fakeY));
    SDL_FreeSurface(animationFrame);

    // Un pixel de control, para saber donde esta el centro
    pixelRGBA(display,
        fixX(this->k->position[0]),
        fixY(this->k->position[1]),
        255, 0, 0, 128
        );
  Sint16 x = k->position[0] - 20, y =k->position[1] - 60 - k->position[2]*.065;
  x = fixX(x);
  y = fixY(y);
  int lonRect = 30;
  const Sint16 vx[4] = {x,x,
      x+ ((float)life/LIFE_PIKMEN)*lonRect,
      x+ ((float)life/LIFE_PIKMEN)*lonRect};
  const Sint16 vy[4] = {y,y+5,y+5,y};

  if(life>0)
    filledPolygonColor(display,vx,vy,4,0xf41c1cff);

  rectangleColor(display,x,y,x+lonRect,y+5,0xffffffff);
}


/*
 *Se aleja del player
 */
void Character::alejarDelPlayer(){
  switch(estado){
    case SEEK_PLAYER:
      estado = ALEJAR_DEL_PLAYER;
      break;
    default:
      break;
  }
}

/*
 * Verifica si tiene un enemigo a 200 pixeles de cercania
 */
bool Pikmen::enemysCerca(){
  float aux[3];
  Kinematic *myK = this->getKinematic();
  for (int cont = 0, n= enemys->size(); cont < n ; cont++ ){
    Kinematic *b = (*enemys)[cont]->getKinematic();
    restarVectores(myK->position,b->position,aux);
    if (abs(aux[0]) < 200 && abs(aux[1]) < 200){
      delete(myK);
      delete(b);
      return true;
    }
    delete (b);
  }
  delete(myK);
  return false;
}

/*
 * Devuelve el enemigo mas cercano en 300 pixeles, de lo contrario NULL
 */
Character* Pikmen::enemyMasCercano(){
  float posRet[3] = {0,0,0},aux[3];
  Character* ret = NULL;
  Kinematic *myK = this->getKinematic();
  for (int cont = 0, n= enemys->size(); cont < n ; cont++ ){
    Kinematic *b = (*enemys)[cont]->getKinematic();
    restarVectores(myK->position,b->position,aux);
    if (abs(aux[0]) < 300 && abs(aux[1]) < 300){
      if (ret == NULL || posRet[0] < abs(aux[0]) || posRet[1] < abs(aux[1])){
        posRet[0] = abs(aux[0]);
        posRet[1] = abs(aux[1]);
        ret = (*enemys)[cont];
      }
    }
    delete (b);
  }
  return ret;
}

/*
* Aplica comportamiento, actualiza la posicion
* y anima sprites (proximamente)
*/
void Pikmen::OnLoop(long time){
  double _3pi4 = 3*M_PI/4;
  double _pi4 = M_PI/4;
  Uint32 current_time;
  Animation *aux;
  Steering* steering = NULL; //= this->getSteering();
  Kinematic *myK = this->getKinematic(), *b = player->getKinematic();
  _flash_pikmen = this;
  State *saux = state->procces(life,myK,b,enemysCerca(),behaviors,max_life);
  if (saux){
    delete(state);
    state= saux;
  }
  steering = state->getSteering();
  delete(myK); delete(b);
  // Verificamos coliciones (collides)
  float *current = (float *) malloc(sizeof(float)*3);
  float *I = (float *) malloc(sizeof(float)*3);
  float *N = (float *) malloc(sizeof(float)*3);

  if(theApp.getCollision(this, &current, &I, &N)){
    // Acomodamos la posicion del jugador inmediatamente
    k->position[0] = current[0];
    k->position[1] = current[1];

    if(N[0]) k->velocity[0] =
      ((k->velocity[0]<0)?1:-1) * k->max_velocity;
    if(N[1]) k->velocity[1] =
      ((k->velocity[1]<0)?1:-1) * k->max_velocity;
  }

  free(current);
  free(I);
  free(N);

  // Agregamos un efecto constante... gravedad
  steering->linear[2] += -0.008;
  update(steering, time);
  delete steering;
  // Hay que animarlo
  // Seleccionamos la animacion adecuada...
  current_time = SDL_GetTicks();
  aux = currentAnimation;
  if(_animation_oldtime+250 < current_time){
    if(k->position[2] > 0){
      currentAnimation = animations[0];
    } else if(k->orientation>=_3pi4 || k->orientation<= -_3pi4){
      currentAnimation = animations[0];
    } else if(k->orientation<=_3pi4 && k->orientation>=_pi4){
      currentAnimation = animations[1];
    } else if(k->orientation<=_pi4 && k->orientation>=-_pi4){
      currentAnimation = animations[2];
    } else {
      currentAnimation = animations[3];
    }
    if(aux != currentAnimation)
      _animation_oldtime = SDL_GetTicks();
  }
  currentAnimation->OnAnimate();

  // El pikmen agrega olores a su medio ambiente
  int radio = 50;
  Node *node = theApp.findNearestNode(this->k->position);
  long currentTimeOlor = SDL_GetTicks();
  if(node && currentTimeOlor-oldTimetoOlor>timeOlor){
    oldTimetoOlor = currentTimeOlor;
    node->addOlor(new Olor(
          rand()%(radio*2) - radio + (*node)[0],
          rand()%(radio*2) - radio + (*node)[1],
          4000
      ));
  }
}

